package com.tianjs.current.lock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Condition 等待通知测试
 * 有界队列
 * 1、当队列为空时，获取元素的线程将被阻塞，直到有新增元素
 * 2、当队列已满时，插入元素的线程将被阻塞，直到队列出现“空位”
 * @author admin
 * @param <T>
 */
public class BoundedQueue<T> {
	
	private Object[] items;
	
	private int addIndex;
	private int removeIndex;
	private int count;//当前队列里元素个数
	
	private Lock lock = new ReentrantLock();
	private Condition notEmpty = lock.newCondition();
	private Condition notFull = lock.newCondition();
	/**
	 * 新增元素
	 * 如果数据已满，则添加元素的线程进入阻塞状态，直到有空位
	 * @param t
	 * @throws InterruptedException 
	 */
	public void add(T t) throws InterruptedException {
		lock.lock();
		try {
			while(count == items.length) {//不采用if,防止过早或意外的通知，符合条件再推出循环
				notFull.await();
			}
			items[addIndex] = t;
			if(++addIndex == items.length) {
				addIndex = 0;
			}
			++count;
			notEmpty.signal();//唤醒处于阻塞状态的删除线程
		} finally {
			lock.unlock();
		}
	}
	
	/**
	 * 从头部删除元素，
	 * 如果数据为空，则删除线程进入阻塞状态，知道有新元素进来
	 * @return
	 * @throws InterruptedException 
	 */
	@SuppressWarnings("unchecked")
	public T remove() throws InterruptedException {
		lock.lock();
		try {
			while(count == 0) {//不采用if,防止过早或意外的通知，符合条件再推出循环
				notEmpty.await();
			}
			Object x = items[removeIndex];
			if(++removeIndex == items.length) {
				removeIndex = 0;
			}
			--count;
			return (T) x;
		} finally {
			lock.unlock();
		}
	}

}
